/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <cmsis_os2.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "cmsis_os2.h"
#include "ohos_init.h"
#include "gpio_if.h"
#include "iot_nfc.h"

#include "ohos_init.h"
#include "iot_demo_def.h"
#include "gas_detection.h"
#include "nativeapi_config.h"
#include "wifi_sta.h"
#include "hal/hal_gpadc.h"
#include "math.h"

#define max_len 128
#define CONFIG_SENSOR_SAMPLE_CYCLE 10000
#define CONFIG_GAS_MEASURE_DELAY 500
#define CN_LAMP_EVENT_ALL   (CN_SWITCH_EVENT_SETSTATUS)
#define CN_SWITCH_EVENT_SETSTATUS  (1<<0)
#define CONFIG_LOCAL_TIMEZONE            8
#define CONFIG_MAX_SEND_DATA_LEN         256
#define INIT_GAS_THRESHOLD               100
#define GAS_ADC_CHANNEL                  0

static const uint16_t GPIO02 = 2;

typedef struct {
    uint32_t GasThreshold;
    uint32_t CurrentGasCONC;
    bool wifiSts;
}ApplicationController;

char g_sendMessage[CONFIG_MAX_SEND_DATA_LEN];
ApplicationController g_appController;

#define TIMER_TICK_NUM 900

extern void RpcClientTest(int32_t* progress);

#define CAL_PPM 20 //校准环境中PPM值
#define RL 1       // RL阻值
float g_R0; //元件在洁净空气中的阻值
uint16_t g_rawData = 0;
uint16_t g_voltData = 0;

/**
 * @brief Convert miniseconds to system ticks
 * @param ms Indicates the mimiseconds to convert
 * @return Returns the corresponding ticks of specified time
 */
static uint32_t Time2Tick(uint32_t ms)
{
    uint64_t ret;
    ret = ((uint64_t)ms * osKernelGetTickFreq()) / CN_MINISECONDS_IN_SECOND;
    return (uint32_t)ret;
}

void AdcOpenCallback(uint16_t rawData, uint16_t voltData) {
    g_rawData = rawData;
    g_voltData = voltData;
}

float GetGasMeasureVoltage(void)
{
    unsigned short voltageTemp = 0;
    int ret =  hal_gpadc_open(HAL_GPADC_CHAN_0, HAL_GPADC_ATP_50MS, NULL);
    if (ret != 0) {
        printf("hal_gpadc_open exec failed \n");
    }
    osDelay(Time2Tick(CONFIG_GAS_MEASURE_DELAY));
    hal_gpadc_get_volt(HAL_GPADC_CHAN_0, &voltageTemp);

    printf("%s voltageTemp :%d\n", __func__, voltageTemp);

    return (float)voltageTemp * 1.8 * 4 / 4096.0;
}

void GasPPMCalibration(void)
{   
    float dataTemp = GetGasMeasureVoltage();

    float RS = (5 - dataTemp) / dataTemp * RL;

    double temp_cali = pow(CAL_PPM / 613.9f, 1 / -2.074f);

    g_R0 = (float)(RS / temp_cali);
    printf("GasPPMCalibration finished g_R0 value:%f\n", g_R0);
}

int GetGasPPM(void)
{
    unsigned int ppm = 0;
    unsigned short data;
    float voltage, RS;
    
    voltage = GetGasMeasureVoltage();
    RS = (5 - voltage) / voltage * RL;     //计算RS
    printf("RS value :%f, g_R0 value :%f\n", RS, g_R0);
    
    double temp = (double)pow((double)(RS / g_R0), -2.074f);
    printf("temp value :%lf\n", temp);

    ppm = (int)(613.9f * temp); //计算ppm

    return ppm;
}

bool GetWifiConnectedStatus(void)
{
    return CheckWifiConnectedStatus();
}

int SendDataToJs(void)
{
    bool wifiSts = GetWifiConnectedStatus();

    char wifiStsStr[16];

    if (wifiSts) {
        strncpy(wifiStsStr, "connected", sizeof(wifiStsStr));
    } else {
        strncpy(wifiStsStr, "disconnected", sizeof(wifiStsStr));
    }

    g_appController.wifiSts = wifiSts;
    memset_s(g_sendMessage, CONFIG_MAX_SEND_DATA_LEN, 0, CONFIG_MAX_SEND_DATA_LEN);
    
    snprintf(g_sendMessage, sizeof(g_sendMessage),"{\"CurrentGasCONC\":\"%d\", \"wifi\":\"%s\"}", g_appController.CurrentGasCONC, wifiStsStr);

    int length = strlen(g_sendMessage);
    g_sendMessage[length] = 0;

    return length;
}

static int JsGetClang(const char* key, char* value)
{
    if ((key == NULL) || (value == NULL)) {
        return ERROR_CODE_PARAM;
    }
    
    int length = SendDataToJs();

    if (length > 0 && length < CONFIG_MAX_SEND_DATA_LEN) {
        strncpy(value, g_sendMessage, length);
        value[length] = 0;
    } else {
        printf(" JsGetClang .value = NULL\r\n");
    }

    return NATIVE_SUCCESS;
}

void JsSetHumidityThreshold(const char *value)
{
    if (value == NULL ) {
        printf("error: JsSetHumidityThreshold value NULL\n");
        return ;
    }
    
    g_appController.GasThreshold = atoi(value);
    printf("value = %s, g_appController.GasThreshold:%d.\n", value, g_appController.GasThreshold);
}

static int JsSetClang(const char* key, const char* value)
{
    if ((key == NULL) || (!IsValidValue(value))) {
        return ERROR_CODE_PARAM;
    }
    printf("%s : %s--%s\n", __func__, key, value);

    if(strncmp(key,"GasThreshold",strlen("GasThreshold")) == 0) {
        JsSetHumidityThreshold(value);
    }
    return  NATIVE_SUCCESS;
}

static void MainTaskEntry(void *arg)
{
    int ret = 0;
    NfcInfo nfcInfo;
    char ssid[BUFF_SIZE] = {0};
    char pwd[BUFF_SIZE] = {0};
    
    g_appController.GasThreshold = INIT_GAS_THRESHOLD;
    g_appController.CurrentGasCONC = 0;
    g_appController.wifiSts = false;
    int32_t remoteFlag = 0;
    while (1) {

        g_appController.CurrentGasCONC = GetGasPPM();
      
        printf("CurrentGasCONC value :%d GasThreshold:%d \n", g_appController.CurrentGasCONC, g_appController.GasThreshold);
        if (g_appController.CurrentGasCONC > g_appController.GasThreshold) {
            remoteFlag = 1;
            RpcClientTest(&remoteFlag);
        } else {
            remoteFlag = 0;
            RpcClientTest(&remoteFlag);
        }
        osDelay(Time2Tick(CONFIG_SENSOR_SAMPLE_CYCLE));
    }
   
}

void StartMainThread(void)
{
    printf("[%s:%d]: %s\n", __FILE__, __LINE__, __func__);
    GasPPMCalibration();
    JsGetClangFuncationRegister(JsGetClang);
    JsSetClangFuncationRegister(JsSetClang);
    osThreadAttr_t attr = {0};
    attr.stack_size = 1024*10;
    attr.priority = 25;
    attr.name = "gas_detection_main_entry";
    if (osThreadNew((osThreadFunc_t)MainTaskEntry, NULL, &attr) == NULL) {
        printf("Failed to create gas_detection_main thread\r\n");
    }
}